Laying the groundwork for interactive reporting & dashboards…

  1. ggplot2 and gridExtra
library(ggplot2)
library(gridExtra)
data(anscombe)
sapply(1:4, function(x) cor(anscombe[, x], anscombe[, x+4]))
[1] 0.8164205 0.8162365 0.8162867 0.8165214
sapply(5:8, function(x) var(anscombe[, x]))
[1] 4.127269 4.127629 4.122620 4.123249
lm(y1 ~ x1, data = anscombe)

Call:
lm(formula = y1 ~ x1, data = anscombe)

Coefficients:
(Intercept)           x1  
     3.0001       0.5001  
p1 <- ggplot(anscombe) + geom_point(aes(x1, y1), color = "darkorange", size = 3) + theme_bw() + scale_x_continuous(breaks = seq(0, 20, 2)) + scale_y_continuous(breaks = seq(0, 12, 2)) + geom_abline(intercept = 3, slope = 0.5, color = "cornflowerblue") + expand_limits(x = 0, y = 0) + labs(title = "dataset 1")
p2 <- ggplot(anscombe) + geom_point(aes(x2, y2), color = "darkorange", size = 3) + theme_bw() + scale_x_continuous(breaks = seq(0, 20, 2)) + scale_y_continuous(breaks = seq(0, 12, 2)) + geom_abline(intercept = 3, slope = 0.5, color = "cornflowerblue") + expand_limits(x = 0, y = 0) + labs(title = "dataset 2")
p3 <- ggplot(anscombe) + geom_point(aes(x3, y3), color = "darkorange", size = 3) + theme_bw() + scale_x_continuous(breaks = seq(0, 20, 2)) + scale_y_continuous(breaks = seq(0, 12, 2)) + geom_abline(intercept = 3, slope = 0.5, color = "cornflowerblue") + expand_limits(x = 0, y = 0) + labs(title = "dataset 3")
p4 <- ggplot(anscombe) + geom_point(aes(x4, y4), color = "darkorange", size = 3) + theme_bw() + scale_x_continuous(breaks = seq(0, 20, 2)) + scale_y_continuous(breaks = seq(0, 12, 2)) + geom_abline(intercept = 3, slope = 0.5, color = "cornflowerblue") + expand_limits(x = 0, y = 0) + labs(title = "dataset 4")
grid.arrange(p1, p2, p3, p4, top = "Anscombe's Quartet")

  1. HTML Widgets

http://www.htmlwidgets.org

2.A Dygraphs

http://www.htmlwidgets.org/showcase_dygraphs.html

Basic plot example:

## standard graphics device
library(stats)
plot(nhtemp, main = "nhtemp data", ylab = "Mean annual temp. in F)")

## using dygraphs
library(dygraphs)
fig <- dygraph(nhtemp, main = "New Haven Temperatures")
fig <- dyAxis(fig, "y", label = "Temp (F)", valueRange = c(40, 60))
fig <- dyOptions(fig, axisLineWidth = 1.5, fillGraph = TRUE, drawGrid = FALSE)
fig
dygraph(nhtemp, main = "New Haven Temperatures") %>% 
  dySeries("V1", label = "Temperature (F)") %>%
  dyLegend(show = "always", hideOnMouseOut = FALSE)
dygraph(nhtemp, main = "New Haven Temperatures") %>% 
  dyRangeSelector()
dygraph(nhtemp, main = "New Haven Temperatures") %>% 
  dyRangeSelector(dateWindow = c("1920-01-01", "1960-01-01"))
dygraph(nhtemp, main = "New Haven Temperatures") %>% 
  dyRangeSelector(height = 20, strokeColor = "")
#Shaded Regions
dygraph(nhtemp, main = "New Haven Temperatures") %>% 
  dyShading(from = "1920-1-1", to = "1930-1-1") %>%
  dyShading(from = "1940-1-1", to = "1950-1-1")
dygraph(nhtemp, main = "New Haven Temperatures") %>% 
  dySeries(label = "Temp (F)", color = "black") %>%
  dyShading(from = "1920-1-1", to = "1930-1-1", color = "#FFE6E6") %>%
  dyShading(from = "1940-1-1", to = "1950-1-1", color = "#CCEBD6")
library(quantmod)
library(dygraphs)
library(quantmod)
getSymbols("MSFT", src = "google", from = "2014-06-01", auto.assign=TRUE)
[1] "MSFT"
ret = ROC(MSFT[, 4])
mn = mean(ret, na.rm = TRUE)
std = sd(ret, na.rm = TRUE)
dygraph(ret, main = "Microsoft Share Price") %>% 
  dySeries("MSFT.Close", label = "MSFT") %>%
  dyShading(from = mn - std, to = mn + std, axis = "y")
getSymbols("MSFT", src = "google", from = "2014-06-01", auto.assign=TRUE)
[1] "MSFT"
dygraph(MSFT[, 4], main = "Microsoft Share Price") %>% 
  dySeries("MSFT.Close", label = "MSFT") %>%
  dyLimit(as.numeric(MSFT[1, 4]), color = "red")
getSymbols(c("MSFT", "HPQ"), src = "google", from = "2014-06-01", auto.assign=TRUE)
[1] "MSFT" "HPQ" 
stocks <- cbind(MSFT[,2:4], HPQ[,2:4])
dygraph(stocks, main = "Microsoft and HP Share Prices") %>% 
  dySeries(c("MSFT.Low", "MSFT.Close", "MSFT.High"), label = "MSFT") %>%
  dySeries(c("HPQ.Low", "HPQ.Close", "HPQ.High"), label = "HPQ")

2.B Plotly

http://www.htmlwidgets.org/showcase_plotly.html

https://plot.ly/r/dashboard/

https://plot.ly/r/shiny-tutorial/

library(ggplot2)
library(plotly)
p <- ggplot(data = diamonds, aes(x = cut, fill = clarity)) +
            geom_bar(position = "dodge")
ggplotly(p)
d <- diamonds[sample(nrow(diamonds), 500), ]
plot_ly(d, x = d$carat, y = d$price, 
        text = paste("Clarity: ", d$clarity),
        mode = "markers", color = d$carat, size = d$carat)
No trace type specified:
  Based on info supplied, a 'scatter' trace seems appropriate.
  Read more about this trace type -> https://plot.ly/r/reference/#scatter
No trace type specified:
  Based on info supplied, a 'scatter' trace seems appropriate.
  Read more about this trace type -> https://plot.ly/r/reference/#scatter

2.C rbokeh

http://www.htmlwidgets.org/showcase_rbokeh.html

library(rbokeh)
figure() %>%
  ly_points(Sepal.Length, Sepal.Width, data = iris,
    color = Species, glyph = Species,
    hover = list(Sepal.Length, Sepal.Width))
figure(width = NULL, height = NULL, legend_location = "top_left") %>%
  ly_quantile(Sepal.Length, group = Species, data = iris)
figure(width = NULL, height = NULL) %>%
  ly_points(Sepal.Length, Sepal.Width, data = iris,
    color = Petal.Width)
tools <- c("pan", "wheel_zoom", "box_zoom", "box_select", "reset")
nms <- expand.grid(names(iris)[1:4], rev(names(iris)[1:4]), stringsAsFactors = FALSE)
splom_list <- vector("list", 16)
for(ii in seq_len(nrow(nms))) {
  splom_list[[ii]] <- figure(width = 200, height = 200, tools = tools,
    xlab = nms$Var1[ii], ylab = nms$Var2[ii]) %>%
    ly_points(nms$Var1[ii], nms$Var2[ii], data = iris,
      color = Species, size = 5, legend = FALSE)
}
grid_plot(splom_list, ncol = 4, same_axes = TRUE, link_data = TRUE)

2.4 DT

http://www.htmlwidgets.org/showcase_datatables.html

library(DT)
datatable(iris, options = list(pageLength = 5))
  1. Interactive Plots - Shiny

http://shiny.rstudio.com/gallery/

Exmaples:

3_Shiny_Basic_Plots

3_Shiny_ToothGrowth_Plots

  1. shinydashboard

https://rstudio.github.io/shinydashboard/

Examples:

4_Shiny_stockVis_basic

4_Shiny_stockapp_tabs

4_Shiny_shinydashboard_basic

4_Shiny_shinydashboard_box

  1. flexdashboard

http://rmarkdown.rstudio.com/flexdashboard/examples.html

Examples:

5_RMD_Flex_ToothGrowth

5_RMD_Flex_Shiny_ToothGrowth

  1. Crosstalk

http://rstudio.github.io/crosstalk/index.html

http://rstudio.github.io/crosstalk/shiny.html

Examples:

6_Crosstalk_Shiny

  1. HTML Templates

https://shiny.rstudio.com/articles/templates.html

https://github.com/nwstephens/nyr2016

Examples:

7_Shiny_htmlTemplates

LS0tCnRpdGxlOiAiSW50ZXJhY3RpdmUgUmVwb3J0aW5nIERhc2hib2FyZHMgaW4gU2hpbnkiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAotLS0KCkxheWluZyB0aGUgZ3JvdW5kd29yayBmb3IgaW50ZXJhY3RpdmUgcmVwb3J0aW5nICYgZGFzaGJvYXJkcy4uLgoKMS4gZ2dwbG90MiBhbmQgZ3JpZEV4dHJhCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKCmRhdGEoYW5zY29tYmUpCgpzYXBwbHkoMTo0LCBmdW5jdGlvbih4KSBjb3IoYW5zY29tYmVbLCB4XSwgYW5zY29tYmVbLCB4KzRdKSkKc2FwcGx5KDU6OCwgZnVuY3Rpb24oeCkgdmFyKGFuc2NvbWJlWywgeF0pKQpsbSh5MSB+IHgxLCBkYXRhID0gYW5zY29tYmUpCgpwMSA8LSBnZ3Bsb3QoYW5zY29tYmUpICsgZ2VvbV9wb2ludChhZXMoeDEsIHkxKSwgY29sb3IgPSAiZGFya29yYW5nZSIsIHNpemUgPSAzKSArIHRoZW1lX2J3KCkgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDIwLCAyKSkgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEyLCAyKSkgKyBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAzLCBzbG9wZSA9IDAuNSwgY29sb3IgPSAiY29ybmZsb3dlcmJsdWUiKSArIGV4cGFuZF9saW1pdHMoeCA9IDAsIHkgPSAwKSArIGxhYnModGl0bGUgPSAiZGF0YXNldCAxIikKcDIgPC0gZ2dwbG90KGFuc2NvbWJlKSArIGdlb21fcG9pbnQoYWVzKHgyLCB5MiksIGNvbG9yID0gImRhcmtvcmFuZ2UiLCBzaXplID0gMykgKyB0aGVtZV9idygpICsgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAyMCwgMikpICsgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxMiwgMikpICsgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMywgc2xvcGUgPSAwLjUsIGNvbG9yID0gImNvcm5mbG93ZXJibHVlIikgKyBleHBhbmRfbGltaXRzKHggPSAwLCB5ID0gMCkgKyBsYWJzKHRpdGxlID0gImRhdGFzZXQgMiIpCnAzIDwtIGdncGxvdChhbnNjb21iZSkgKyBnZW9tX3BvaW50KGFlcyh4MywgeTMpLCBjb2xvciA9ICJkYXJrb3JhbmdlIiwgc2l6ZSA9IDMpICsgdGhlbWVfYncoKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMjAsIDIpKSArIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMTIsIDIpKSArIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDMsIHNsb3BlID0gMC41LCBjb2xvciA9ICJjb3JuZmxvd2VyYmx1ZSIpICsgZXhwYW5kX2xpbWl0cyh4ID0gMCwgeSA9IDApICsgbGFicyh0aXRsZSA9ICJkYXRhc2V0IDMiKQpwNCA8LSBnZ3Bsb3QoYW5zY29tYmUpICsgZ2VvbV9wb2ludChhZXMoeDQsIHk0KSwgY29sb3IgPSAiZGFya29yYW5nZSIsIHNpemUgPSAzKSArIHRoZW1lX2J3KCkgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDIwLCAyKSkgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEyLCAyKSkgKyBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAzLCBzbG9wZSA9IDAuNSwgY29sb3IgPSAiY29ybmZsb3dlcmJsdWUiKSArIGV4cGFuZF9saW1pdHMoeCA9IDAsIHkgPSAwKSArIGxhYnModGl0bGUgPSAiZGF0YXNldCA0IikKCmdyaWQuYXJyYW5nZShwMSwgcDIsIHAzLCBwNCwgdG9wID0gIkFuc2NvbWJlJ3MgUXVhcnRldCIpCmBgYAoKMi4gSFRNTCBXaWRnZXRzCgpodHRwOi8vd3d3Lmh0bWx3aWRnZXRzLm9yZwoKMi5BIER5Z3JhcGhzCgpodHRwOi8vd3d3Lmh0bWx3aWRnZXRzLm9yZy9zaG93Y2FzZV9keWdyYXBocy5odG1sCgpCYXNpYyBwbG90IGV4YW1wbGU6CgpgYGB7cn0KIyMgc3RhbmRhcmQgZ3JhcGhpY3MgZGV2aWNlCmxpYnJhcnkoc3RhdHMpCnBsb3Qobmh0ZW1wLCBtYWluID0gIm5odGVtcCBkYXRhIiwgeWxhYiA9ICJNZWFuIGFubnVhbCB0ZW1wLiBpbiBGKSIpCgpgYGAKCgpgYGB7cn0KIyMgdXNpbmcgZHlncmFwaHMKbGlicmFyeShkeWdyYXBocykKZmlnIDwtIGR5Z3JhcGgobmh0ZW1wLCBtYWluID0gIk5ldyBIYXZlbiBUZW1wZXJhdHVyZXMiKQpmaWcgPC0gZHlBeGlzKGZpZywgInkiLCBsYWJlbCA9ICJUZW1wIChGKSIsIHZhbHVlUmFuZ2UgPSBjKDQwLCA2MCkpCmZpZyA8LSBkeU9wdGlvbnMoZmlnLCBheGlzTGluZVdpZHRoID0gMS41LCBmaWxsR3JhcGggPSBUUlVFLCBkcmF3R3JpZCA9IEZBTFNFKQpmaWcKYGBgCgpgYGB7cn0KZHlncmFwaChuaHRlbXAsIG1haW4gPSAiTmV3IEhhdmVuIFRlbXBlcmF0dXJlcyIpICU+JSAKICBkeVNlcmllcygiVjEiLCBsYWJlbCA9ICJUZW1wZXJhdHVyZSAoRikiKSAlPiUKICBkeUxlZ2VuZChzaG93ID0gImFsd2F5cyIsIGhpZGVPbk1vdXNlT3V0ID0gRkFMU0UpCgpgYGAKCmBgYHtyfQpkeWdyYXBoKG5odGVtcCwgbWFpbiA9ICJOZXcgSGF2ZW4gVGVtcGVyYXR1cmVzIikgJT4lIAogIGR5UmFuZ2VTZWxlY3RvcigpCmBgYAoKYGBge3J9CmR5Z3JhcGgobmh0ZW1wLCBtYWluID0gIk5ldyBIYXZlbiBUZW1wZXJhdHVyZXMiKSAlPiUgCiAgZHlSYW5nZVNlbGVjdG9yKGRhdGVXaW5kb3cgPSBjKCIxOTIwLTAxLTAxIiwgIjE5NjAtMDEtMDEiKSkKYGBgCgpgYGB7cn0KZHlncmFwaChuaHRlbXAsIG1haW4gPSAiTmV3IEhhdmVuIFRlbXBlcmF0dXJlcyIpICU+JSAKICBkeVJhbmdlU2VsZWN0b3IoaGVpZ2h0ID0gMjAsIHN0cm9rZUNvbG9yID0gIiIpCmBgYAoKYGBge3J9CiNTaGFkZWQgUmVnaW9ucwpkeWdyYXBoKG5odGVtcCwgbWFpbiA9ICJOZXcgSGF2ZW4gVGVtcGVyYXR1cmVzIikgJT4lIAogIGR5U2hhZGluZyhmcm9tID0gIjE5MjAtMS0xIiwgdG8gPSAiMTkzMC0xLTEiKSAlPiUKICBkeVNoYWRpbmcoZnJvbSA9ICIxOTQwLTEtMSIsIHRvID0gIjE5NTAtMS0xIikKYGBgCgpgYGB7cn0KZHlncmFwaChuaHRlbXAsIG1haW4gPSAiTmV3IEhhdmVuIFRlbXBlcmF0dXJlcyIpICU+JSAKICBkeVNlcmllcyhsYWJlbCA9ICJUZW1wIChGKSIsIGNvbG9yID0gImJsYWNrIikgJT4lCiAgZHlTaGFkaW5nKGZyb20gPSAiMTkyMC0xLTEiLCB0byA9ICIxOTMwLTEtMSIsIGNvbG9yID0gIiNGRkU2RTYiKSAlPiUKICBkeVNoYWRpbmcoZnJvbSA9ICIxOTQwLTEtMSIsIHRvID0gIjE5NTAtMS0xIiwgY29sb3IgPSAiI0NDRUJENiIpCmBgYAoKYGBge3J9CmxpYnJhcnkocXVhbnRtb2QpCmxpYnJhcnkoZHlncmFwaHMpCgpsaWJyYXJ5KHF1YW50bW9kKQoKZ2V0U3ltYm9scygiTVNGVCIsIHNyYyA9ICJnb29nbGUiLCBmcm9tID0gIjIwMTQtMDYtMDEiLCBhdXRvLmFzc2lnbj1UUlVFKQoKcmV0ID0gUk9DKE1TRlRbLCA0XSkKbW4gPSBtZWFuKHJldCwgbmEucm0gPSBUUlVFKQpzdGQgPSBzZChyZXQsIG5hLnJtID0gVFJVRSkKZHlncmFwaChyZXQsIG1haW4gPSAiTWljcm9zb2Z0IFNoYXJlIFByaWNlIikgJT4lIAogIGR5U2VyaWVzKCJNU0ZULkNsb3NlIiwgbGFiZWwgPSAiTVNGVCIpICU+JQogIGR5U2hhZGluZyhmcm9tID0gbW4gLSBzdGQsIHRvID0gbW4gKyBzdGQsIGF4aXMgPSAieSIpCgoKYGBgCmBgYHtyfQpnZXRTeW1ib2xzKCJNU0ZUIiwgc3JjID0gImdvb2dsZSIsIGZyb20gPSAiMjAxNC0wNi0wMSIsIGF1dG8uYXNzaWduPVRSVUUpCmR5Z3JhcGgoTVNGVFssIDRdLCBtYWluID0gIk1pY3Jvc29mdCBTaGFyZSBQcmljZSIpICU+JSAKICBkeVNlcmllcygiTVNGVC5DbG9zZSIsIGxhYmVsID0gIk1TRlQiKSAlPiUKICBkeUxpbWl0KGFzLm51bWVyaWMoTVNGVFsxLCA0XSksIGNvbG9yID0gInJlZCIpCmBgYAoKYGBge3J9CmdldFN5bWJvbHMoYygiTVNGVCIsICJIUFEiKSwgc3JjID0gImdvb2dsZSIsIGZyb20gPSAiMjAxNC0wNi0wMSIsIGF1dG8uYXNzaWduPVRSVUUpCgpzdG9ja3MgPC0gY2JpbmQoTVNGVFssMjo0XSwgSFBRWywyOjRdKQpkeWdyYXBoKHN0b2NrcywgbWFpbiA9ICJNaWNyb3NvZnQgYW5kIEhQIFNoYXJlIFByaWNlcyIpICU+JSAKICBkeVNlcmllcyhjKCJNU0ZULkxvdyIsICJNU0ZULkNsb3NlIiwgIk1TRlQuSGlnaCIpLCBsYWJlbCA9ICJNU0ZUIikgJT4lCiAgZHlTZXJpZXMoYygiSFBRLkxvdyIsICJIUFEuQ2xvc2UiLCAiSFBRLkhpZ2giKSwgbGFiZWwgPSAiSFBRIikKYGBgCgoKMi5CIFBsb3RseQoKaHR0cDovL3d3dy5odG1sd2lkZ2V0cy5vcmcvc2hvd2Nhc2VfcGxvdGx5Lmh0bWwKCmh0dHBzOi8vcGxvdC5seS9yL2Rhc2hib2FyZC8KCmh0dHBzOi8vcGxvdC5seS9yL3NoaW55LXR1dG9yaWFsLwoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwbG90bHkpCnAgPC0gZ2dwbG90KGRhdGEgPSBkaWFtb25kcywgYWVzKHggPSBjdXQsIGZpbGwgPSBjbGFyaXR5KSkgKwogICAgICAgICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpCmdncGxvdGx5KHApCmBgYAoKYGBge3J9CmQgPC0gZGlhbW9uZHNbc2FtcGxlKG5yb3coZGlhbW9uZHMpLCA1MDApLCBdCnBsb3RfbHkoZCwgeCA9IGQkY2FyYXQsIHkgPSBkJHByaWNlLCAKICAgICAgICB0ZXh0ID0gcGFzdGUoIkNsYXJpdHk6ICIsIGQkY2xhcml0eSksCiAgICAgICAgbW9kZSA9ICJtYXJrZXJzIiwgY29sb3IgPSBkJGNhcmF0LCBzaXplID0gZCRjYXJhdCkKYGBgCgoyLkMgcmJva2VoCgpodHRwOi8vd3d3Lmh0bWx3aWRnZXRzLm9yZy9zaG93Y2FzZV9yYm9rZWguaHRtbAoKYGBge3J9CmxpYnJhcnkocmJva2VoKQpmaWd1cmUoKSAlPiUKICBseV9wb2ludHMoU2VwYWwuTGVuZ3RoLCBTZXBhbC5XaWR0aCwgZGF0YSA9IGlyaXMsCiAgICBjb2xvciA9IFNwZWNpZXMsIGdseXBoID0gU3BlY2llcywKICAgIGhvdmVyID0gbGlzdChTZXBhbC5MZW5ndGgsIFNlcGFsLldpZHRoKSkKYGBgCgpgYGB7cn0KZmlndXJlKHdpZHRoID0gTlVMTCwgaGVpZ2h0ID0gTlVMTCwgbGVnZW5kX2xvY2F0aW9uID0gInRvcF9sZWZ0IikgJT4lCiAgbHlfcXVhbnRpbGUoU2VwYWwuTGVuZ3RoLCBncm91cCA9IFNwZWNpZXMsIGRhdGEgPSBpcmlzKQpgYGAKCgpgYGB7cn0KZmlndXJlKHdpZHRoID0gTlVMTCwgaGVpZ2h0ID0gTlVMTCkgJT4lCiAgbHlfcG9pbnRzKFNlcGFsLkxlbmd0aCwgU2VwYWwuV2lkdGgsIGRhdGEgPSBpcmlzLAogICAgY29sb3IgPSBQZXRhbC5XaWR0aCkKYGBgCgpgYGB7cn0KdG9vbHMgPC0gYygicGFuIiwgIndoZWVsX3pvb20iLCAiYm94X3pvb20iLCAiYm94X3NlbGVjdCIsICJyZXNldCIpCm5tcyA8LSBleHBhbmQuZ3JpZChuYW1lcyhpcmlzKVsxOjRdLCByZXYobmFtZXMoaXJpcylbMTo0XSksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKc3Bsb21fbGlzdCA8LSB2ZWN0b3IoImxpc3QiLCAxNikKZm9yKGlpIGluIHNlcV9sZW4obnJvdyhubXMpKSkgewogIHNwbG9tX2xpc3RbW2lpXV0gPC0gZmlndXJlKHdpZHRoID0gMjAwLCBoZWlnaHQgPSAyMDAsIHRvb2xzID0gdG9vbHMsCiAgICB4bGFiID0gbm1zJFZhcjFbaWldLCB5bGFiID0gbm1zJFZhcjJbaWldKSAlPiUKICAgIGx5X3BvaW50cyhubXMkVmFyMVtpaV0sIG5tcyRWYXIyW2lpXSwgZGF0YSA9IGlyaXMsCiAgICAgIGNvbG9yID0gU3BlY2llcywgc2l6ZSA9IDUsIGxlZ2VuZCA9IEZBTFNFKQp9CmdyaWRfcGxvdChzcGxvbV9saXN0LCBuY29sID0gNCwgc2FtZV9heGVzID0gVFJVRSwgbGlua19kYXRhID0gVFJVRSkKYGBgCgoyLjQgRFQKCmh0dHA6Ly93d3cuaHRtbHdpZGdldHMub3JnL3Nob3djYXNlX2RhdGF0YWJsZXMuaHRtbAoKYGBge3J9CmxpYnJhcnkoRFQpCmRhdGF0YWJsZShpcmlzLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSkpCmBgYAoKCjMuIEludGVyYWN0aXZlIFBsb3RzIC0gU2hpbnkKCmh0dHA6Ly9zaGlueS5yc3R1ZGlvLmNvbS9nYWxsZXJ5LwoKRXhtYXBsZXM6CgozX1NoaW55X0Jhc2ljX1Bsb3RzCgozX1NoaW55X1Rvb3RoR3Jvd3RoX1Bsb3RzCgo0LiBzaGlueWRhc2hib2FyZAoKaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9zaGlueWRhc2hib2FyZC8KCkV4YW1wbGVzOgoKNF9TaGlueV9zdG9ja1Zpc19iYXNpYwoKNF9TaGlueV9zdG9ja2FwcF90YWJzCgo0X1NoaW55X3NoaW55ZGFzaGJvYXJkX2Jhc2ljCgo0X1NoaW55X3NoaW55ZGFzaGJvYXJkX2JveAoKNS4gZmxleGRhc2hib2FyZAoKaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9mbGV4ZGFzaGJvYXJkL2V4YW1wbGVzLmh0bWwKCkV4YW1wbGVzOgoKNV9STURfRmxleF9Ub290aEdyb3d0aAoKNV9STURfRmxleF9TaGlueV9Ub290aEdyb3d0aAoKNi4gQ3Jvc3N0YWxrCgpodHRwOi8vcnN0dWRpby5naXRodWIuaW8vY3Jvc3N0YWxrL2luZGV4Lmh0bWwKCmh0dHA6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9jcm9zc3RhbGsvc2hpbnkuaHRtbAoKRXhhbXBsZXM6Cgo2X0Nyb3NzdGFsa19TaGlueQoKNy4gSFRNTCBUZW1wbGF0ZXMKCmh0dHBzOi8vc2hpbnkucnN0dWRpby5jb20vYXJ0aWNsZXMvdGVtcGxhdGVzLmh0bWwKCmh0dHBzOi8vZ2l0aHViLmNvbS9ud3N0ZXBoZW5zL255cjIwMTYKCkV4YW1wbGVzOgoKN19TaGlueV9odG1sVGVtcGxhdGVzCg==